package com.cdc.http.http2;

import android.text.TextUtils;
import android.webkit.MimeTypeMap;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSocketFactory;

/**
 * Created by admin on 2018/3/24.
 */

public abstract class Request<T> {

    private String boundary=createBoundary();
    private String startBoundary="--"+boundary;
    private String endBoundary=startBoundary+"--";
    private String url;

    private RequestMethod method;

    private Map<String,String> mRequestHeads;

    Map<String,String> getmRequestHeads(){
        return mRequestHeads;
    }
    private String mContentType;

    private boolean enableFormData;





    private SSLSocketFactory mSSLSocketFactory;
    private HostnameVerifier mHostnameVerifier;

    public void setmSSLSocketFactory(SSLSocketFactory mSSLSocketFactory) {
        this.mSSLSocketFactory = mSSLSocketFactory;
    }

    public SSLSocketFactory getmSSLSocketFactory() {
        return mSSLSocketFactory;
    }

    public HostnameVerifier getmHostnameVerifier() {
        return mHostnameVerifier;
    }

    public void setmHostnameVerifier(HostnameVerifier mHostnameVerifier) {
        this.mHostnameVerifier = mHostnameVerifier;
    }

    /**
     * 获取请求的地址
     * @return
     */
    public String getUrl() {
        StringBuilder urlBuilder=new StringBuilder(url);
        String params=buildParamString();
        if(!method.isOutputMethod()){
            if(params.length()>0 && url.contains("?") && url.contains("=")){
                urlBuilder.append("&");
            }else if(params.length()>0 && !url.endsWith("?")){
                urlBuilder.append("?");
            }
            urlBuilder.append(params);
        }
        return urlBuilder.toString();
    }

    public RequestMethod getMethod() {
        return method;
    }

    List<KeyValue> getKeyValues() {
        return keyValues;
    }

    private List<KeyValue> keyValues;

    public Request(String url){
        this(url, RequestMethod.GET);
    }

    public Request(String url,RequestMethod method){
        this.url=url;
        this.method=method;
        mRequestHeads=new HashMap<>();
        keyValues=new ArrayList<>();
    }

    public void setHead(String key,String value){
        mRequestHeads.put(key,value);
    }
    public void add(String key,String value){
        keyValues.add(new KeyValue(key,value));
    }

    public void add(String key,File value){
        keyValues.add(new KeyValue(key,value));
    }

    public void setmContentType(String mContentType){
        this.mContentType=mContentType;
    }

    public long getContentLength (){
        //post类型的请求时才需要,一般的post请求不需要;form类的String表单,form类的带文件的表单
        //
        CounterOutPutStream counterOutPutStream=new CounterOutPutStream();
        try {
            onWriteBopdy(counterOutPutStream);
        } catch (Exception e) {
            return 0;
        }
        return counterOutPutStream.get();
    }

    /***
     * 写出表单数据
     * @param outputStream
     * @throws Exception
     */
    private void writeFormData(OutputStream outputStream) throws IOException {
        for (KeyValue keyValue : keyValues) {
            String key=keyValue.getKey();
            Object value=keyValue.getValue();
            if(value instanceof  File){
                writeFormFileData(outputStream,key,(File)value);
            }else{
                writeFormStringData(outputStream,key,(String)value);
            }
            outputStream.write("\r\n".getBytes());
        }
        outputStream.write(endBoundary.getBytes());
    }

    private String mCharSet="utf-8";


    private void writeFormStringData(OutputStream outputStream, String key, String value) throws IOException {
        StringBuilder builder=new StringBuilder();
        builder.append(startBoundary).append("\r\n");
        builder.append("Content-Disposition: form-data; name=\"").append(key).append("\"").append("\r\n");
        builder.append("Content-Type: text/plain; charset=\"").append(mCharSet).append("\"").append("\r\n");
        builder.append("\r\n\r\n");
        builder.append(value);
        outputStream.write(builder.toString().getBytes(mCharSet));



    }

    /**
     * 写出表单中的File item
     * @param outputStream
     * @param key
     * @param value
     */
    private void writeFormFileData(OutputStream outputStream, String key, File value) throws IOException {
        StringBuilder builder=new StringBuilder();
        builder.append(startBoundary).append("\r\n");
        String filename=value.getName();
        String mimeType="application/octet-stream";
        if(MimeTypeMap.getSingleton().hasExtension(filename)){
            String extension=MimeTypeMap.getFileExtensionFromUrl(filename);
            mimeType=MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
        };
        builder.append("Content-Disposition: form-data; name=\"").append(key).append("\"; filename=\"")
                .append(filename).append("\"").append("\r\n");
        builder.append("Content-Type: ").append(mimeType);
        builder.append("\r\n").append("\r\n");
        outputStream.write(builder.toString().getBytes(mCharSet));
        if(outputStream instanceof CounterOutPutStream){
            ((CounterOutPutStream)outputStream).write(value.length());
        }else{
            InputStream inputStream=new FileInputStream(value);
            byte[] buffer=new byte[2048];
            int len=0;
            while((len=inputStream.read(buffer))!=-1){
                outputStream.write(buffer,0,len);
            }

        }

    }

    public void  onWriteBopdy(OutputStream outputStream) throws IOException{
        if(enableFormData || hasFile()){
            writeFormData(outputStream);
        }else{
            writeStringData(outputStream);
        }
    }

    private void writeStringData(OutputStream outputStream) throws IOException {
        String params=buildParamString();
        outputStream.write(params.getBytes());
    }


    public String getmContentType(){
        if(!TextUtils.isEmpty(mContentType)){
            return  mContentType;
        }else if(enableFormData || hasFile()){//是否强制表单提交  是否有文件
            return "multipart/form-data; boundary="+boundary;
        }

        return "application/x-www-form-urlencoded";
    }
    protected boolean hasFile(){
        for (KeyValue keyValue : keyValues) {
            Object value=keyValue.getValue();
            if(value instanceof File){
                return true;
            }
        }
        return false;
    }

    public void formData(boolean enable){
        if(!method.isOutputMethod()){
            throw  new IllegalArgumentException(method.getValue()+" is not support outputstream");
        }
        enableFormData=enable;
    }

    protected String createBoundary(){
        StringBuilder stringBuilder=new StringBuilder("--CDC");
        stringBuilder.append(UUID.randomUUID());
        return stringBuilder.toString();
    }

    /**
     * 解析服务器的数据
     * @param responseBody
     */
    public abstract T parseResponse(byte[] responseBody);

    /**
     * 构建以key=value&key1=value1形式的String 参数
     * @return
     */
    protected String buildParamString(){
        StringBuilder stringBuilder=new StringBuilder();
        for (KeyValue keyValue : keyValues) {
            Object value=keyValue.getValue();
            if(value instanceof  String){
                stringBuilder.append("&");
                try {
                    stringBuilder.append(URLEncoder.encode(keyValue.getKey(),mCharSet));
                    stringBuilder.append("=");
                    stringBuilder.append(URLEncoder.encode((String)value,mCharSet));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

            }
        }
        if(stringBuilder.length()>0){
            stringBuilder.deleteCharAt(0);
        }
        return  stringBuilder.toString();
    }


}
